package com.docmgmt.mvp.generator;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import java.util.logging.Level;

/**
 * MyBatis-Plus 代码生成器 v3.0
 *
 * 功能：基于v3.0数据库（32张表）批量生成Entity、Mapper、Service
 *
 * 使用方法：
 * 1. 确保Docker环境已启动（MySQL已运行）
 * 2. 修改main方法中的GENERATE_MODE：
 *    - "ALL": 生成所有32张表（会覆盖已有文件）
 *    - "MISSING": 只生成缺失的23张表（推荐）
 * 3. 运行main方法
 * 4. 生成的代码位于：
 *    - Entity: src/main/java/com/docmgmt/mvp/entity/
 *    - Mapper: src/main/java/com/docmgmt/mvp/mapper/
 *    - Mapper XML: src/main/resources/mapper/
 *    - Service: src/main/java/com/docmgmt/mvp/service/
 *
 * @author Dora
 * @version 3.0
 */
public class Dora {

    /**
     * 生成模式：
     * - "ALL": 生成所有32张表（会覆盖已有文件）
     * - "MISSING": 只生成缺失的23张表（推荐）
     */
    private static final String GENERATE_MODE = "MISSING";

    /**
     * 已存在的Entity（9张表，不需要重新生成）
     */
    private static final String[] EXISTING_TABLES = {
        "sys_user", "sys_role", "sys_permission", "sys_user_role",
        "doc_folder", "doc_file",
        "ai_dialog",
        "kb_file_mapping",
        // "user" 是遗留类，不在此列表
    };

    /**
     * v3.0 数据库32张表（按模块分类）- 2025-11-02 更新
     */
    // 系统用户模块（7张表）
    private static final String[] SYS_TABLES = {
        "sys_role", "sys_user", "sys_department", "sys_user_group",
        "sys_user_group_member", "sys_permission", "sys_user_permission"
    };

    // 文档管理模块（9张表）
    private static final String[] DOC_TABLES = {
        "doc_folder", "doc_file", "doc_file_version", "version_policy",
        "doc_tag", "doc_file_tag", "doc_user_favorite",
        "doc_access_history", "doc_comment"
    };

    // 权限管理模块（2张表）
    private static final String[] PERM_TABLES = {
        "perm_folder_permission", "perm_file_share"
    };

    // 知识库模块（6张表）
    private static final String[] KB_TABLES = {
        "knowledge_base", "kb_file_mapping", "file_kb_sync",
        "kb_member", "kb_sync_task", "kb_sync_log"
    };

    // AI模块（3张表）
    private static final String[] AI_TABLES = {
        "ai_dialog", "ai_conversation", "ai_feedback"
    };

    // 协作通知模块（2张表）
    private static final String[] COLLAB_TABLES = {
        "collab_notification", "collab_activity_log"
    };

    // 系统管理模块（3张表）
    private static final String[] ADMIN_TABLES = {
        "sys_operation_log", "sys_audit_log", "sys_config"
    };

    private static final Logger logger = Logger.getLogger(Dora.class.getName());

    public static void main(String[] args) {
        // 合并所有表（共32张表）
        String[] allTablesArray = concat(SYS_TABLES, DOC_TABLES, PERM_TABLES, KB_TABLES, AI_TABLES, COLLAB_TABLES, ADMIN_TABLES);

        // 根据模式过滤表
        List<String> tablesToGenerate;
        if ("MISSING".equals(GENERATE_MODE)) {
            // 只生成缺失的表
            List<String> existingList = Arrays.asList(EXISTING_TABLES);
            tablesToGenerate = Arrays.stream(allTablesArray)
                .filter(table -> !existingList.contains(table))
                .collect(java.util.stream.Collectors.toList());

            logger.info("=============================================");
            logger.info("MyBatis-Plus 代码生成器 v3.0 - 增量模式");
            logger.info("=============================================");
            logger.info("总计32张表，已存在" + EXISTING_TABLES.length + "张，将生成缺失的" + tablesToGenerate.size() + "张：");
            tablesToGenerate.forEach(table -> logger.info("  - " + table));
        } else {
            // 生成所有表
            tablesToGenerate = Arrays.asList(allTablesArray);

            logger.info("=============================================");
            logger.info("MyBatis-Plus 代码生成器 v3.0 - 全量模式");
            logger.info("=============================================");
            logger.info("将生成所有32张表的代码（会覆盖已有文件）：");
            tablesToGenerate.forEach(table -> logger.info("  - " + table));
        }
        logger.info("=============================================");

        // 数据库连接信息（从Docker .env文件读取）
        String url = "jdbc:mysql://localhost:3306/doc_management?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
        String username = "doc_user";
        String password = "DocUser@2025";

        // 项目路径（修复：直接使用当前目录）
        String projectPath = System.getProperty("user.dir");
        String outputDir = projectPath + "/src/main/java";
        String mapperXmlDir = projectPath + "/src/main/resources/mapper";

        FastAutoGenerator.create(url, username, password)
            // 全局配置
            .globalConfig(builder -> {
                builder.author("Dora")
                    .outputDir(outputDir)
                    .disableOpenDir()  // 禁止打开输出目录
                    .dateType(DateType.TIME_PACK)  // 使用java.time包
                    .commentDate("yyyy-MM-dd");
            })
            // 包配置
            .packageConfig(builder -> {
                builder.parent("com.docmgmt.mvp")
                    .entity("entity")
                    .mapper("mapper")
                    .service("service")
                    .serviceImpl("service.impl")
                    .pathInfo(Collections.singletonMap(OutputFile.xml, mapperXmlDir));
            })
            // 策略配置
            .strategyConfig(builder -> {
                builder
                    // 设置要生成的表
                    .addInclude(tablesToGenerate)
                    // 设置过滤表前缀（生成Entity时去掉前缀）
                    .addTablePrefix("doc_", "kb_", "ai_", "sys_", "perm_", "collab_", "file_")

                    // Entity策略
                    .entityBuilder()
                    .enableLombok()  // 启用Lombok
                    .enableTableFieldAnnotation()  // 启用字段注解
                    .enableChainModel()  // 启用链式模型
                    .idType(IdType.AUTO)  // 主键自增
                    .logicDeleteColumnName("is_deleted")  // 逻辑删除字段
                    .addTableFills(
                        new Column("created_at", FieldFill.INSERT),
                        new Column("updated_at", FieldFill.INSERT_UPDATE)
                    )
                    .formatFileName("%sEntity")  // 实体类名格式

                    // Mapper策略
                    .mapperBuilder()
                    .enableBaseResultMap()  // 启用BaseResultMap
                    .enableBaseColumnList()  // 启用BaseColumnList
                    .formatMapperFileName("%sMapper")
                    .formatXmlFileName("%sMapper")

                    // Service策略
                    .serviceBuilder()
                    .formatServiceFileName("%sService")
                    .formatServiceImplFileName("%sServiceImpl");
            })
            // 模板引擎
            .templateEngine(new FreemarkerTemplateEngine())
            // 执行
            .execute();

        logger.info("=============================================");
        logger.info("代码生成完成！");
        logger.info("Entity: " + outputDir + "/com/docmgmt/mvp/entity/");
        logger.info("Mapper: " + outputDir + "/com/docmgmt/mvp/mapper/");
        logger.info("Mapper XML: " + mapperXmlDir);
        logger.info("Service: " + outputDir + "/com/docmgmt/mvp/service/");
        logger.info("=============================================");
    }

    /**
     * 合并多个数组
     */
    @SafeVarargs
    private static <T> T[] concat(T[]... arrays) {
        int totalLength = 0;
        for (T[] arr : arrays) {
            totalLength += arr.length;
        }

        @SuppressWarnings("unchecked")
        T[] result = (T[]) java.lang.reflect.Array.newInstance(
            arrays[0].getClass().getComponentType(), totalLength
        );

        int currentIndex = 0;
        for (T[] arr : arrays) {
            System.arraycopy(arr, 0, result, currentIndex, arr.length);
            currentIndex += arr.length;
        }

        return result;
    }
}
